import { command, serviceId, notifyCharacteristic, writeCharacteristic } from "./const";
import { promisify } from "../libs/util";
import Peripheral from "../Peripheral";
import { ab2hex, str2ab } from "../libs/util";
import phera from "../const/phera";
import { okmsg, failmsg } from "../const/msg";

/**
 * 血压手表
 */
class BPWatch extends Peripheral {

  constructor() {
    super();

    this.peripherals = {};
    this.connectedDeviceId = null;
    this.comState = "pause";
  }

  /**
   * 启动插件
   * @public
   * @returns {Promise<*>}
   */
  async start() {
    let res = await this.getBluetoothAdapterState();
    console.log('[start]', res);
    let { discovering, available } = res;
    if (discovering === false) {
      let res = await (promisify(phera.openBluetoothAdapter))();
      return Promise.resolve(res.res || res);
    } else if (available) {
      return Promise.resolve(okmsg);
    } else {
      return Promise.reject(failmsg);
    }
  }

  /**
   * 开始扫描设备列表
   * @param {Function} cb 回调函数，参数未设备列表
   */
  async scanStart(cb) {
    let { discovering, available } = await this.getBluetoothAdapterState();
    if (!discovering) {
      let res = await (promisify(phera.startBluetoothDevicesDiscovery))();
      console.log(`[startScan]`, res);
    }
    let res = await (promisify(phera.getBluetoothDevices))();
    let { devices } = res;
    this.handleGetDevices(devices);

    this.onBluetoothDeviceFound();
  }

  /**
   * 发现设备
   * @private
   */
  onBluetoothDeviceFound() {
    phera.onBluetoothDeviceFound(res => {
      console.log('[onBluetoothDeviceFound]', res);
      const { devices } = res;
      this.handleGetDevices(devices);
    });
  }

  /**
   * 处理新增设备
   * @private
   * @param {Array} devices 
   */
  handleGetDevices(devices) {
    Array.isArray(devices) && devices.forEach(device => {
      this.getEvents("__handleGetDevices").forEach(cb => {
        if (!device.name && !device.localName) {
          return;
        }
        // console.log("[GetDevice]", device);
        const { name, deviceId } = device;
        if (name.indexOf("BPW") == -1) {
          return;
        }
        const peripherals = this.peripherals;
        if (!peripherals[deviceId]) {
          peripherals[deviceId] = device;
          cb(peripherals);
        }
      });
    });
  }

  /**
   * 监听血压手表列表
   * @public
   * @param {Function} cb 监听回调函数
   */
  notifyDeviceFound(cb) {
    return this.addEvent('__handleGetDevices', cb);
  }

  /**
   * 停止扫描设备
   * @public
   * @returns {Promise<*>} 调用状态
   */
  scanStop() {
    return promisify(phera.stopBluetoothDevicesDiscovery)();
  }

  /**
   * 连接设备并获取特征值
   * @public
   * @param {String} deviceId 设备Id
   * @returns {Promise<*>}
   */
  connect(deviceId) {
    if (!deviceId) {
      console.log('[connect#peripherals]', this.peripherals);
      const peripherals = this.peripherals;
      const deviceIdlist = Object.keys(peripherals);
      // TODO: 选中设备
      deviceId = deviceIdlist[0];
    }
    return promisify(phera.createBLEConnection)({ deviceId })
      .then(async (res) => {
        this.connected = true;
        phera.stopBluetoothDevicesDiscovery();
        this.connectedDeviceId = deviceId;
        let data = await promisify(phera.getBLEDeviceServices)({ deviceId });
        data = data.res || data;

        console.log('[connect#getBLEDeviceServices]', data);

        const { services } = data;

        const service = services[2],
          serviceId = service.uuid;
        this.serviceId = serviceId;

        console.log('connect#resolve', res);
        return Promise.resolve(res.res || res);
      }).catch(err => {
        phera.stopBluetoothDevicesDiscovery();
        return Promise.reject(err);
      });
  }

  /**
   * 获取设备特征值
   * @private
   */
  getBLEDeviceCharacteristics() {
    const { connectedDeviceId: deviceId, serviceId } = this.state;
    return promisify(phera.getBLEDeviceCharacteristics)({ deviceId, serviceId });
  }

  /**
   * 开始测量
   * @public
   */
  async startMeasure() {
    return this.sendCommand(command.startCommand);
  }

  /**
   * 停止测量
   * @public
   */
  async stopMeasure() {
    return this.sendCommand(command.stopCommand);
  }

  /**
   * @private
   * @param {Array} commandcode
   * @returns {Promise<*>} 
   */
  sendCommand(commandcode) {
    const params = {
      deviceId: this.connectedDeviceId,
      serviceId: this.serviceId,
      characteristicId: writeCharacteristic,
      value: str2ab(commandcode)
    };
    console.log(`[sendCommand]`, params);
    return promisify(phera.writeBLECharacteristicValue)(params);
  }

  /**
   * 监听设备数据
   * @public
   * @param {Function} cb 监听回调函数
   * @returns {Function} 移除监听的函数
   */
  onDataChange(cb) {
    return this.addEvent('__onDataChange', cb);
  }

  /**
   * 检测特征值变化
   * @private
   */
  onCharacteristicValueChange() {
    phera.onBLECharacteristicValueChange(res => {
      // const { characteristicId, value } = res;
      this.getEvents('__onDataChange').forEach(cb => cb(res));
    });
  }

  /**
   * 结束插件
   * @public
   */
  async stop() {
    let deviceId = this.connectedDeviceId;
    phera.closeBLEConnection({ deviceId });
  }

}

export default BPWatch;
